using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.CodeDom;
using Plossum.CommandLine;
using Refly.CodeDom;
using System.IO;
using System.Collections.Specialized;
using System.Threading;
using System.Collections;
using Refly.CodeDom.Expressions;
using System.Reflection;

namespace AKJ.Sharepoint.SPConstantGen
{
    class Program
    {
        static void Main(string[] args)
        {
            CmdOptions options = new CmdOptions();
            
            CommandLineParser parser = new CommandLineParser(options);            
            parser.Parse();
            Console.WriteLine(parser.UsageInfo.GetHeaderAsString(78));

            if (parser.HasErrors)
            {
                Console.WriteLine(parser.UsageInfo.GetErrorsAsString(78));
                Console.WriteLine(parser.UsageInfo.GetOptionsAsString(78));                
                return;
            }

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(options.Url))
                {
                    using (SPWeb web = site.RootWeb)
                    {
                        GenereateClass(web, options.Path, options.Namespace);
                    }
                }
            }
        );
        }

        static void GenereateClass(SPWeb web, string filepath, string namesp)
        {
            if (filepath == "")
                filepath = Environment.CurrentDirectory;

            NamespaceDeclaration ns = new NamespaceDeclaration(namesp);

            ClassDeclaration aclass = ns.AddClass("SPConstant");
            aclass.OutputType = ClassOutputType.Struct;

            AddFieldsRoot(web, aclass);
            AddLists(web, aclass);
            AddWebs(web, aclass);

            CodeGenerator gen = new CodeGenerator();
            gen.Options.BlankLinesBetweenMembers = false;
            gen.CreateFolders = false;
            gen.Copyright = "Anders K. Jacobsen";            
            gen.Options.VerbatimOrder = true;

            gen.GenerateCode(filepath, ns);

            FileInfo file = new FileInfo(filepath + "/" + "SPConstant.cs");
            StreamReader reader = file.OpenText();
            string str = reader.ReadToEnd();

            Console.WriteLine(str);

        }

        static void AddFieldsRoot(SPWeb web, ClassDeclaration aclass)
        {
            ClassDeclaration fieldsStruct = aclass.AddClass("Fields");
            fieldsStruct.OutputType = ClassOutputType.Struct;
            fieldsStruct.Conformer.Camelize = false;
            fieldsStruct.Doc.Summary.AddText("Contains all SPField's in the Sharepoint Applicaiton");

            AddFieldCollection(web.Fields, fieldsStruct);
        }

        static void AddFieldCollection(SPFieldCollection fields, ClassDeclaration fieldsStruct)
        {
            foreach (SPField field in fields)
            {
                if (fieldsStruct.NestedClasses.Contains(field.StaticName))
                    continue;

                ClassDeclaration fieldStruct = fieldsStruct.AddClass(field.StaticName);
                fieldStruct.OutputType = ClassOutputType.Struct;
                fieldStruct.Conformer.Camelize = false;
                fieldStruct.Doc.Summary.AddText(field.Description == "" ? "No description has been specified" : field.Description);

                FieldDeclaration nameField = fieldStruct.AddField(typeof(string), "StaticName");
                nameField.Attributes = MemberAttributes.Public | MemberAttributes.Const;
                nameField.InitExpression = new PrimitiveExpression(field.StaticName);
                nameField.Doc.Summary.AddText(field.StaticName);

                FieldDeclaration descriptionField = fieldStruct.AddField(typeof(string), "DescriptionText");
                descriptionField.Attributes = MemberAttributes.Public | MemberAttributes.Const;
                descriptionField.InitExpression = new PrimitiveExpression(field.Description);
                descriptionField.Doc.Summary.AddText(field.Description == "" ? "No description has been specified" : field.Description);
            }
        }

        static void AddLists(SPWeb web, ClassDeclaration aclass)
        {
            ClassDeclaration lists = aclass.AddClass("Lists");
            lists.OutputType = ClassOutputType.Struct;
            lists.Conformer.Camelize = false;
            lists.Doc.Summary.AddText("Contains all SPList's in the Sharepoint Applicaiton");

            StringCollection existing = new StringCollection();

            foreach (SPList list in web.Lists)
            {
                string listTitleNoWhitespace = list.Title.Replace(" ", "");

                if (lists.NestedClasses.Contains(listTitleNoWhitespace))
                    continue;

                ClassDeclaration listStruct = lists.AddClass(listTitleNoWhitespace);
                listStruct.OutputType = ClassOutputType.Struct;
                listStruct.Conformer.Camelize = false;
                listStruct.Doc.Summary.AddText(list.Description == "" ? "No description has been specified" : list.Description);

                FieldDeclaration nameField = listStruct.AddField(typeof(string), "Title");
                nameField.Attributes = MemberAttributes.Public | MemberAttributes.Const;
                nameField.InitExpression = new PrimitiveExpression(list.Title);
                nameField.Doc.Summary.AddText(list.Title);

                FieldDeclaration descriptionField = listStruct.AddField(typeof(string), "Description");
                descriptionField.Attributes = MemberAttributes.Public | MemberAttributes.Const;
                descriptionField.InitExpression = new PrimitiveExpression(list.Description);
                descriptionField.Doc.Summary.AddText(list.Description == "" ? "No description has been specified" : list.Description);

                ClassDeclaration fieldsStruct = listStruct.AddClass("Fields");
                fieldsStruct.OutputType = ClassOutputType.Struct;
                fieldsStruct.Conformer.Camelize = false;
                fieldsStruct.Doc.Summary.AddText("All fields for List \"" + list.Title + "\"");

                AddFieldCollection(list.Fields, fieldsStruct);                
            }
        }

        static void AddWeb(SPWeb web, ClassDeclaration aclass, string name)
        {
            ClassDeclaration currentWeb = aclass.AddClass(name);
            currentWeb.OutputType = ClassOutputType.Struct;
            currentWeb.Conformer.Camelize = false;
            currentWeb.Doc.Summary.AddText(web.Description);

            FieldDeclaration nameField = currentWeb.AddField(typeof(string), "Name");
            nameField.Attributes = MemberAttributes.Public | MemberAttributes.Const;
            nameField.InitExpression = new PrimitiveExpression(web.Name);
            nameField.Doc.Summary.AddText(web.Name);

            FieldDeclaration descriptionField = currentWeb.AddField(typeof(string), "Description");
            descriptionField.Attributes = MemberAttributes.Public | MemberAttributes.Const;
            descriptionField.InitExpression = new PrimitiveExpression(web.Description);
            descriptionField.Doc.Summary.AddText(web.Description == "" ? "No description has been specified" : web.Description);
        }

        static void AddWebs(SPWeb web, ClassDeclaration aclass)
        {
            ClassDeclaration webs = aclass.AddClass("Webs");
            webs.OutputType = ClassOutputType.Struct;
            webs.Conformer.Camelize = false;
            webs.Doc.Summary.AddText("Contains all SPWeb's in the Sharepoint Applicaiton");

            AddWeb(web, webs, "RootWeb");

            StringCollection existing = new StringCollection();

            foreach (SPWeb currentweb in web.Webs)
            {
                string webNameNoWhitespace = web.Name.Replace(" ", "");

                if (webs.NestedClasses.Contains(webNameNoWhitespace))
                    continue;

                AddWeb(currentweb, webs, currentweb.Name);
            }
        }

        
    }
}
